#include <stdio.h>


/* use these for random number generation */
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>

#include <rsa.h>
#include <big_math.h>

#define BIT_LENGTH_OF_N	 	2048
#define BIT_LENGTH_OF_INT	32
#define RSA_E_VALUE		65537


int test_generate_prime();
int test_generate_key(const int int_length_of_p);
int test_encrypt_decrypt(const int int_length_of_p);


int main(int argc, char** argv) {
   int i = 0;
   int bit_length_of_p = 0;
   int int_length_of_p = 0;

   struct timeval *p_time;

   printf("Testing gettimeofday()\n");
   gettimeofday(p_time, NULL);
   printf("got %d.%06d\n", p_time->tv_sec, p_time->tv_usec);

   printf("Testing rsa routines.\n");

   //srand((unsigned)(time(0)));

   bit_length_of_p = BIT_LENGTH_OF_N / 2;
   int_length_of_p = bit_length_of_p / BIT_LENGTH_OF_INT;


   test_generate_prime();
   // test_generate_key(RSA_E_VALUE, int_length_of_p);
   test_encrypt_decrypt(int_length_of_p);

   return 0;
}

int test_generate_prime() {
   int i = 0;
   big_int *test_big_int = (big_int *)calloc(1, sizeof(big_int));

   if (test_big_int == NULL) {
      fprintf(stderr, "Failed to create test_big_int: main.\n");
   }

   generate_prime(test_big_int);

   print_big_int(test_big_int);


   /* a test that might be feasible given the big machine
      sitting under here would be to ensure that division
      by every number less than p gives 0 as a result...
      but that's a HUGE test...and right now we don't even
      care if p is really prime, or if e and p - 1 are
      relatively prime */


}

/* what this test does:
   1 generate two large primes p and q
   2 compute n = pq and phi = (p - 1)(q - 1)
   3 compute d, 1 < d < phi, such that d is the modular multiplicative
     inverse of mod(e, phi)
   4 use e and n to encrypt a message
   5 use d and n to decrypt the message
   
   ...actually, we will probably do steps 1 to 3 offline
   (I have a spreadsheet with the Extended Euclidian Algorithm
   in a magic box.)
   */
int test_encrypt_decrypt(const int int_length_of_p) {
   /* make m about half the size of p, just because it has to
      be large so the encryption isn't trivial, but less than
      n so the algorithm still works */
   big_int *p_big_int_p = NULL;
   big_int *p_big_int_q = NULL;
   int *p_n_array = NULL;
   int *p_m_array = NULL;

   int int_length_of_m = 0;
   int int_length_of_n = 0;
   int i = 0;

   int ares = 2;
   int bres = 2;
   int np = 95;
   int n = 9;
   int r = 16;

   /* int m = 855;
   int k = 2753;
   int np = 1889;
   int n = 3233;
   int r = 4096; */

   int mont_prod_res = 0;
   int mod_exp_res = 0;

   int mask_temp = 0;
   int m = 0;
   int k = 0;

   rsa_private_key_t *p_private_key;
   rsa_public_key_t *p_public_key;

/*
   printf("Testing bit_length_p.\n");

   i = sizeof(int) * 8 - 1;
   for (i; i >= 0; i--) {
      printf("i = %d\n", i);
      mask_temp = 1 << i;

      printf("mask = %x\n", mask_temp);
      printf("mask result = %x\n\n", mask_temp & 8192);

      if ((mask_temp & 8192) != 0) {
         break;
      }
   }
   printf("Bit length of 8192 is: %d\n\n", i + 1);

*/
   r = 4096;
   n = 2503;
   printf("r = %d, n = %d\n", r, n);

   ares = 1598;
   bres = 2288;

   mont_prod_res = mont_prod(ares, bres, np, n, r);

   printf("mont_prod(%d, %d) = %d\n", ares, bres, mont_prod_res);
   printf("expected value is 130\n");

   ares = 918;
   bres = 1773;

   mont_prod_res = mont_prod(ares, bres, np, n, r);
   
   printf("mont_prod(%d, %d) = %d\n", ares, bres, mont_prod_res);
   printf("expected value is 1149\n");

   ares = 1185;
   bres = 1454;

   mont_prod_res = mont_prod(ares, bres, np, n, r);
   
   printf("mont_prod(%d, %d) = %d\n\n", ares, bres, mont_prod_res);
   printf("expected value is 87\n");

   r = 8192;
   n = 5263;
   printf("r = %d, n = %d\n", r, n);

   ares = 1757;
   bres = 5060;

   mont_prod_res = mont_prod(ares, bres, np, n, r);

   printf("mont_prod(%d, %d) = %d\n", ares, bres, mont_prod_res);
   printf("expected value is 2640\n");

   ares = 4548;
   bres = 2658;

   mont_prod_res = mont_prod(ares, bres, np, n, r);

   printf("mont_prod(%d, %d) = %d\n", ares, bres, mont_prod_res);
   printf("expected value is 4359\n");

   ares = 4483;
   bres = 3463;

   mont_prod_res = mont_prod(ares, bres, np, n, r);

   printf("mont_prod(%d, %d) = %d\n\n", ares, bres, mont_prod_res);
   printf("expected value is 562\n");

   r = 16384;
   n = 14057;
   printf("r = %d, n = %d\n", r, n);

   ares = 10604;
   bres = 4143;

   mont_prod_res = mont_prod(ares, bres, np, n, r);

   printf("mont_prod(%d, %d) = %d\n", ares, bres, mont_prod_res);
   printf("expected value is 8018\n");

   ares = 7322;
   bres = 10930;

   mont_prod_res = mont_prod(ares, bres, np, n, r);

   printf("mont_prod(%d, %d) = %d\n", ares, bres, mont_prod_res);
   printf("expected value is 9727\n");

   ares = 1131;
   bres = 12430;

   mont_prod_res = mont_prod(ares, bres, np, n, r);

   printf("mont_prod(%d, %d) = %d\n\n", ares, bres, mont_prod_res);
   printf("expected value is 13973\n");

   m = 141280;
   k = 1023849;
   np = -11321;
   n = 32247;
   r = 4096;

   printf("message = %d, k = %d, n = %d, r = %d\n", m, k, n, r);

   mod_exp_res = mod_exp(m, k, np, n, r);

/*
   k = 9;
   mod_exp_res = mod_exp(m, k, np, n, r);

   printf("k = %d, mod_exp_res = %d\n", k, mod_exp_res);

   k = 20;
   mod_exp_res = mod_exp(m, k, np, n, r);

   printf("k = %d, mod_exp_res = %d\n", k, mod_exp_res);
   
   k = 1120;
   mod_exp_res = mod_exp(m, k, np, n, r);

   printf("k = %d, mod_exp_res = %d\n", k, mod_exp_res);
*/
   p_private_key = calloc(1, sizeof(rsa_private_key_t));
   if (p_private_key == NULL) {
      printf("Failed to create private_key.\n");
      return EXIT_FAILURE;
   }

   p_public_key = calloc(1, sizeof(rsa_public_key_t));
   if (p_public_key == NULL) {
      printf("Failed to create public_key.\n");
      return EXIT_FAILURE;
   }

   int_length_of_n = 2 * int_length_of_p;

   p_big_int_p = calloc(1, sizeof(big_int));
   if (p_big_int_p == NULL) {
      printf("Failed to create p_array.\n");
      return EXIT_FAILURE;
   }

   p_big_int_q = calloc(1, sizeof(big_int));
   if (p_big_int_q == NULL) {
      printf("Failed to create q_array.\n");
      return EXIT_FAILURE;
   }

   int_length_of_m = int_length_of_p / 2;
   p_m_array = calloc(int_length_of_m, sizeof(int));
   if (p_m_array == NULL) {
      printf("Failed to create m_array.\n");
      return EXIT_FAILURE;
   }

   if (generate_prime(p_big_int_p) != EXIT_SUCCESS) {
      printf("Failed to generate prime p.\n");
      return EXIT_FAILURE;
   }

   if (generate_prime(p_big_int_q) != EXIT_SUCCESS) {
      printf("Failed to generate prime q.\n");
      return EXIT_FAILURE;
   }

   /* we made p and q the same length, 
      and we're multiplying them together, 2
      signed ints, which give us an int of
      length 2 * length_of_p
    */ 
   /*
   bm_multiply(p_p_array, int_length_of_p,
      p_q_array, int_length_of_p,
      p_n_array, int_length_of_n);
   */

   /* create a random plain-text number to encrypt */
   for (i = 0; i < int_length_of_m; i++) {
      p_m_array[i] = rand();
   }

   p_public_key->e_value = RSA_E_VALUE;
   p_public_key->p_n_array = p_n_array;



   
}


